package com.huawang.mdesign.model.service.inter;

import cn.hutool.core.collection.CollectionUtil;
import com.huawang.business.constants.SlotDataType;
import com.huawang.business.dto.ModelPropertyInfo;
import com.huawang.business.dto.ValueSpecificationInfo;
import com.huawang.business.vo.InstanceVo;
import com.huawang.business.vo.SelectElementNode;
import com.huawang.business.vo.display.ShowAttribute;
import com.huawang.business.vo.display.SlotAttr;
import com.huawang.core.definition.mof.UMLDefinitionConstants;
import com.huawang.core.definition.mof.cmof.reflection.impl.BasicRElement;
import com.huawang.core.definition.mof.instances.MetaClassInstance;
import com.huawang.mdesign.model.service.constant.ClassTypeEnum;
import com.huawang.mdesign.model.service.dto.property.MeasurementDTO;
import com.huawang.mdesign.model.service.request.property.SlotDTO;
import com.huawang.mdesign.model.service.facade.util.BatchQueryExecutor;
import com.huawang.mdesign.model.service.vo.SlotValueVo;
import com.huawang.mdesign.model.service.vo.SlotVo;
import com.huawang.mdesign.model.service.vo.display.MeasurementAttr;
import com.huawang.mdesign.model.service.vo.uaf.MeasurementStateVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author cdl
 */
@RequiredArgsConstructor
@Service
@Primary
@Slf4j
public class MeasurementService extends BatchQueryExecutor {

    private static final String PREFIX = "Measurement";

    private final SimulationService simulationService;

    /**
     * 根据度量参数，获得度量map
     *
     * @param measurement 度量
     * @return 度量列表
     */
    @NotNull
    public Map<String, List<InstanceVo>> getMeasurements(MeasurementDTO measurement) {
        if(Objects.nonNull(measurement.getFlag()) && measurement.getFlag().booleanValue()) {
            return getMeasurementsV2(measurement);
        }
        return Optional.ofNullable(measurement.getClassifiers())
                .filter(CollectionUtils::isNotEmpty)
                .map(classifiers -> {
                    String projectId = measurement.getProjectId();
                    Map<String, MetaClassInstance> map = internalUmlService.fetchInstanceByIds(classifiers, projectId)
                            .stream()
                            .collect(Collectors.toMap(BasicRElement::getId, e -> e, (i, j) -> j));
                    return classifiers.stream()
                            .filter(StringUtils::isNotBlank)
                            .collect(Collectors.toMap(
                                    e -> e,
                                    e -> getActualMeasurements(projectId, map.get(e)),
                                    (i, j) -> j));
                }).orElse(Collections.emptyMap());
    }

    /**
     * 根据度量参数，获得度量map
     *
     * @param measurement 度量
     * @return 度量列表
     */
    @NotNull
    public Map<String, List<InstanceVo>> getMeasurementsV2(MeasurementDTO measurement) {
        String projectId = measurement.getProjectId();
        Map<String, List<MeasurementStateVo>> instanceMeasurementMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(measurement.getClassifiers())) {
            internalUmlService.fetchInstanceByIds(measurement.getClassifiers(), projectId)
                    .stream()
                    .filter(instance -> internalUmlService.checkInstanceType(projectId, instance, UMLDefinitionConstants.UAF_PropertySet))
                    .forEach(instance -> {
                        List<MeasurementStateVo> measurementVos = fetchMeasurementFromPropertySet(projectId, instance, new ArrayList<>());
                        instanceMeasurementMap.put(instance.getUUID(), measurementVos);
                    });
        }
        return convertMeasurementVoToInstanceVo(projectId, instanceMeasurementMap);
    }

    /**
     * 将Map中的MeasurementVo转换成InstanceVo
     * @param projectId
     * @param instanceMeasurementMap
     * @return
     */
    @NotNull
    private Map<String, List<InstanceVo>> convertMeasurementVoToInstanceVo(@NotNull String projectId, @NotNull Map<String, List<MeasurementStateVo>> instanceMeasurementMap) {
        Map<String, List<InstanceVo>> result = new HashMap<>();
        if(!instanceMeasurementMap.isEmpty()) {
            Set<MetaClassInstance> models = new HashSet<>();
            instanceMeasurementMap.forEach((key, measurementVos) -> {
                for(MeasurementStateVo measurementVo : measurementVos) {
                    models.add(measurementVo.getExtendMeasurement());
                    models.addAll(measurementVo.getParents());
                    if(Objects.nonNull(measurementVo.getMeasurement())) {
                        models.add(measurementVo.getMeasurement());
                    }
                }
            });
            Map<String, ModelPropertyInfo> modelPropertyInfoMap = modelPropertyInfoService.createModelPropertyInfoMap(projectId, new ArrayList<>(models),
                    Stream.of(UMLDefinitionConstants.NamedElement_name, UMLDefinitionConstants.TypedElement_type, UMLDefinitionConstants.Property_defaultValue).collect(Collectors.toList()));
            instanceMeasurementMap.forEach((key, value) -> result.put(key, convertMeasurementVoToInstanceVo(projectId, value, modelPropertyInfoMap)));
        }
        return result;
    }

    /**
     * 将List中的MeasurementVo转换成InstanceVo
     * @param projectId
     * @param measurementVos
     * @param modelPropertyInfoMap
     * @return
     */
    @NotNull
    private List<InstanceVo> convertMeasurementVoToInstanceVo(@NotNull String projectId, @NotNull List<MeasurementStateVo> measurementVos,
                                                              @NotNull Map<String, ModelPropertyInfo> modelPropertyInfoMap) {
        List<InstanceVo> instanceVos = new ArrayList<>();
        if(!measurementVos.isEmpty()) {
            Set<String> measurementIds = new HashSet<>();
            for(MeasurementStateVo measurementVo : measurementVos) {
                Optional.ofNullable(measurementVo.getExtendMeasurement()).ifPresent(m -> {
                    if(!measurementIds.contains(m.getId())) {
                        measurementIds.add(m.getId());
                        InstanceVo instanceVo = new InstanceVo();
                        instanceVo.setId(m.getId());
                        instanceVo.setOwnerId(m.getOwnerId());
                        Optional.ofNullable(m.getMetaClass())
                                .ifPresent(mc -> instanceVo.setMetaClass(mc.getName()));
                        Optional.ofNullable(m.getAppliedStereotypes())
                                .filter(CollectionUtils::isNotEmpty)
                                .ifPresent(k -> instanceVo.setAppliedStereotypes(new ArrayList<>(k)));
                        setMeasurementAttr(projectId, instanceVo, measurementVo, modelPropertyInfoMap);
                        instanceVos.add(instanceVo);
                    }
                });
            }
        }
        return instanceVos;
    }

    /**
     * 设置Measurement属性内容
     * @param projectId
     * @param instanceVo
     * @param measurementVo
     * @param modelPropertyInfoMap
     */
    private void setMeasurementAttr(@NotNull String projectId, @NotNull InstanceVo instanceVo,
                                    @NotNull MeasurementStateVo measurementVo,
                                    @NotNull Map<String, ModelPropertyInfo> modelPropertyInfoMap) {
        MeasurementAttr prop = new MeasurementAttr();
        prop.setStereotype(PREFIX);
        ShowAttribute<MeasurementAttr> showAttribute = new ShowAttribute<>();
        instanceVo.setShowAttribute(showAttribute);
        showAttribute.setExtraAttribute(prop);

        ModelPropertyInfo measurementPropertyInfo = modelPropertyInfoMap.get(measurementVo.getExtendMeasurement().getId());
        if(measurementPropertyInfo != null) {
            instanceVo.setName(measurementPropertyInfo.queryStringValue(UMLDefinitionConstants.NamedElement_name));
            Optional.ofNullable(measurementPropertyInfo.queryInstanceValue(UMLDefinitionConstants.TypedElement_type)).
                    ifPresent(type -> {
                        prop.setTypeName(internalUmlService.queryStringProperty(projectId, type, UMLDefinitionConstants.NamedElement_name));
                        prop.setTypeId(type.getUUID());
                    });
            Optional.ofNullable(measurementPropertyInfo.queryInstanceValue(UMLDefinitionConstants.Property_defaultValue)).
                    ifPresent(defaultValue -> {
                        ValueSpecificationInfo valueSpecificationInfo = internalSpecificationService.queryValueFromValueSpecification(projectId, defaultValue);
                        if(Objects.nonNull(valueSpecificationInfo) && Objects.nonNull(valueSpecificationInfo.getValue())) {
                            prop.setDefaultValue(valueSpecificationInfo.getValue().toString());
                        }
                    });
        }
        Optional.ofNullable(measurementVo.getMeasurement()).ifPresent(measurement -> {
            ModelPropertyInfo mPropertyInfo = modelPropertyInfoMap.get(measurement.getId());
            Optional.ofNullable(mPropertyInfo).ifPresent(p -> prop.setMeasurementName(p.queryStringValue(UMLDefinitionConstants.NamedElement_name)));
        });
        Optional.ofNullable(measurementVo.getParents()).filter(CollectionUtils::isNotEmpty).ifPresent(parents -> {
            StringBuilder nameSpace = new StringBuilder();
            for(int i=0;i<parents.size();i++) {
                ModelPropertyInfo parentPropertyInfo = modelPropertyInfoMap.get(parents.get(i).getId());
                if(parentPropertyInfo != null) {
                    String name = parentPropertyInfo.queryStringValue(UMLDefinitionConstants.NamedElement_name);
                    nameSpace.append(Objects.nonNull(name)?name:"");
                    nameSpace.append(i+1 == parents.size()?"":".");
                }
            }
            prop.setNamespace(nameSpace.toString());
        });
    }

    /**
     * 从PropertySet模型中获取Measurement属性
     * @param projectId
     * @param propertySet
     * @param measurementParents
     * @return
     */
    @NotNull
    private List<MeasurementStateVo> fetchMeasurementFromPropertySet(String projectId, MetaClassInstance propertySet, List<MetaClassInstance> measurementParents) {
        List<MeasurementStateVo> measurementVos = new ArrayList<>();
        //当前的propertySet模型是不是起点
        boolean currentPropertySet = measurementParents.isEmpty();
        if(!measurementParents.contains(propertySet)) {
            measurementParents.add(propertySet);
        } else {
            return Collections.emptyList();
        }
        List<MetaClassInstance> attrs = internalUmlService.queryListInstanceProperty(projectId, propertySet, UMLDefinitionConstants.Classifier_attribute);
        modelPropertyInfoService.createModelPropertyInfoList(projectId, attrs, Collections.singletonList(UMLDefinitionConstants.TypedElement_type)).forEach(
            attrProperty -> {
                MetaClassInstance attrInstance = attrProperty.getInstance();
                //只有Measurement属性才需要显示
                if(internalUmlService.checkInstanceType(projectId, attrInstance, UMLDefinitionConstants.UAF_Measurement)) {
                    MetaClassInstance typeInstance = attrProperty.queryInstanceValue(UMLDefinitionConstants.TypedElement_type);
                    List<MeasurementStateVo> measurementChildren = null;
                    if(internalUmlService.checkInstanceType(projectId, typeInstance, UMLDefinitionConstants.UAF_PropertySet)) {
                        //如果属性类型是PropertySet，则需要递归查看是否有Measurement属性
                        measurementChildren = fetchMeasurementFromPropertySet(projectId, typeInstance, measurementParents);
                    }
                    if(CollectionUtils.isNotEmpty(measurementChildren)) {
                        if(currentPropertySet) {
                            measurementChildren.stream().forEach(m -> m.setMeasurement(attrInstance));
                        }
                        measurementVos.addAll(measurementChildren);
                    } else {
                        //Measurement属性
                        MeasurementStateVo measurementVo = createMeasurementVo(measurementParents, attrInstance);
                        measurementVos.add(measurementVo);
                    }
                }
            }
        );
        measurementParents.remove(propertySet);
        return measurementVos;
    }

    /**
     * 创建MeasurementVo
     * @param measurementParents
     * @param metaClassInstance
     * @return
     */
    @NotNull
    private MeasurementStateVo createMeasurementVo(List<MetaClassInstance> measurementParents, MetaClassInstance metaClassInstance) {
        MeasurementStateVo measurementVo = new MeasurementStateVo();
        List<MetaClassInstance> parents = new ArrayList<>(measurementParents);
        if(!parents.isEmpty()) {
            parents.remove(0);
        }
        measurementVo.setParents(parents);
        measurementVo.setExtendMeasurement(metaClassInstance);
        return measurementVo;
    }

    /**
     * 获得关联的度量集
     *
     * @param projectId  项目id
     * @param classifier 分类器
     * @return 度量集
     */
    @NotNull
    public Set<String> getAssociatedMeasurementSet(String projectId, String classifier) {
        //Asset,Resource,Standard,MeasurementSet
        List<MetaClassInstance> instances = internalUmlService.querySpecifiedInstanceList(projectId,
                UMLDefinitionConstants.UAF_PropertySet);

        Map<String, List<MetaClassInstance>> classifierMap = getChildren(projectId, instances);

        Queue<String> queue = new LinkedList<>();
        Optional.ofNullable(classifier).filter(StringUtils::isNotBlank).ifPresent(queue::offer);

        Set<String> measurementSet = new HashSet<>();
        getAssociatedMeasurementSet(queue, measurementSet, instances, classifierMap, getType(projectId, reduce(classifierMap)));
        return measurementSet;
    }

    /**
     * 获得度量集子项
     *
     * @param projectId 项目id
     * @param instances 实例集合
     * @return 子节点
     */
    @NotNull
    public Map<String, List<MetaClassInstance>> getChildren(String projectId, List<MetaClassInstance> instances) {
        return getChildren(projectId, instances, UMLDefinitionConstants.UAF_Measurement);
    }

    /**
     * 通过设置map，获得关联的度量集
     *
     * @param queue          队列
     * @param measurementSet 度量集
     * @param classifiers    分类器
     * @param classifierMap  分类器映射
     * @param type           类型映射
     */
    private void getAssociatedMeasurementSet(Queue<String> queue,
                                             Set<String> measurementSet,
                                             List<MetaClassInstance> classifiers,
                                             Map<String, List<MetaClassInstance>> classifierMap,
                                             Map<String, String> type) {
        if (queue.isEmpty()) {
            return;
        }

        String classifier = queue.poll();
        Optional.ofNullable(classifiers)
                .filter(CollectionUtils::isNotEmpty)
                .filter(e -> StringUtils.isNotBlank(classifier))
                .ifPresent(list ->
                        list.forEach(k ->
                                Optional.ofNullable(classifierMap.get(k.getId()))
                                        .filter(CollectionUtils::isNotEmpty)
                                        .filter(e -> e.stream().anyMatch(v -> Objects.equals(type.get(v.getId()), classifier)))
                                        .filter(e -> !measurementSet.contains(k.getId()))
                                        .ifPresent(e -> {
                                            measurementSet.add(k.getId());
                                            queue.offer(k.getId());
                                        })
                        )
                );

        if (!queue.isEmpty()) {
            getAssociatedMeasurementSet(queue, measurementSet, classifiers, classifierMap, type);
        }
    }

    /**
     * 根据度量参数，获得分类器的插槽map
     *
     * @param measurement 度量
     * @return 度量下的插槽
     */
    @NotNull
    public Map<String, List<SlotDTO>> getSlotsOfClassifiers(MeasurementDTO measurement) {
        return Optional.ofNullable(measurement.getClassifiers())
                .filter(CollectionUtils::isNotEmpty)
                .map(k -> k.stream()
                        .filter(StringUtils::isNotBlank)
                        .collect(Collectors.toMap(
                                e -> e,
                                e -> getSlotsOfClassifier(measurement.getProjectId(), e),
                                (i, j) -> j)))
                .orElse(Collections.emptyMap());
    }

    /**
     * 获得插槽列表
     *
     * @param measurement 度量
     * @return 插槽集合
     */
    @NotNull
    public Map<String, List<SlotDTO>> getSlots(MeasurementDTO measurement) {
        String projectId = measurement.getProjectId();
        Map<String, List<SlotDTO>> result = new HashMap<>();

        getSlotsOfClassifiers(measurement).forEach((k, v) -> {
            List<SlotDTO> slots = new ArrayList<>();
            result.put(k, slots);

            v.stream().filter(e -> StringUtils.isNotBlank(e.getInstanceId())).forEach(e -> {
                slots.add(e);
                querySlotsRecursive(projectId, e.getInstanceId(), slots, e.getSlots());
            });
        });
        return result;
    }

    /**
     * 递归获得插槽
     *
     * @param projectId 项目id
     * @param parentId  父节点id
     * @param slots     插槽
     * @param slotList  子插槽
     */
    private void querySlotsRecursive(String projectId, String parentId, List<SlotDTO> slots, List<SlotVo> slotList) {
        Optional.ofNullable(slotList)
                .filter(CollectionUtils::isNotEmpty)
                .ifPresent(list -> list.stream()
                        .filter(e -> StringUtils.isNotBlank(e.getSlotId()))
                        .filter(e -> Objects.equals(e.getDataType(), SlotDataType.INSTANCE.value()))
                        .map(SlotVo::getValues)
                        .filter(CollectionUtils::isNotEmpty)
                        .forEach(v -> v.stream()
                                .map(SlotValueVo::getValue)
                                .filter(Objects::nonNull)
                                .map(String::valueOf)
                                .forEach(instanceId ->
                                        Optional.ofNullable(internalUmlService.fetchInstance(instanceId, projectId))
                                                .filter(e -> internalUmlService.checkInstanceType(projectId, e,
                                                        UMLDefinitionConstants.UAF_ActualMeasurementSet))
                                                .map(e -> internalUmlService.queryListInstanceProperty(projectId, e,
                                                        UMLDefinitionConstants.InstanceSpecification_classifier))
                                                .filter(CollectionUtils::isNotEmpty)
                                                .map(e -> e.get(0))
                                                .map(BasicRElement::getId)
                                                .ifPresent(e ->
                                                        querySlotsRecursive(projectId, instanceId, slots,
                                                                getSlots(projectId, instanceId, e, slots, parentId)
                                                        )
                                                )
                                ))
                );
    }

    /**
     * 根据分类器获得其相关的插槽
     *
     * @param projectId  项目id
     * @param classifier 分类器
     * @return 插槽
     */
    @NotNull
    private List<SlotDTO> getSlotsOfClassifier(String projectId, String classifier) {
        List<SlotDTO> slots = new ArrayList<>();
        getInstancesByClassifier(projectId, classifier)
                .stream()
                .map(SelectElementNode::getInstanceId)
                .filter(StringUtils::isNotBlank)
                .forEach(e -> getSlots(projectId, e, classifier, slots, null));
        return slots;
    }

    /**
     * 获得插槽列表
     *
     * @param projectId    项目id
     * @param instanceId   实例id
     * @param classifierId 分类器
     * @param slots        插槽
     * @param parentId     父节点id
     * @return 插槽
     */
    @NotNull
    private List<SlotVo> getSlots(String projectId, String instanceId, String classifierId, List<SlotDTO> slots, String parentId) {
        return Optional.ofNullable(instanceId)
                .filter(StringUtils::isNotBlank)
                .filter(e -> StringUtils.isNotBlank(classifierId))
                .map(e -> propertyGroupService.queryInstanceSlots(projectId, e, classifierId))
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> {
                    e.removeIf(k -> StringUtils.isBlank(k.getSlotId()));
                    slots.add(new SlotDTO(parentId, instanceId, e));
                    return e;
                }).orElse(Collections.emptyList());
    }

    /**
     * 根据分类器获得实例列表
     *
     * @param projectId  项目id
     * @param classifier 分类器
     * @return 可选择节点
     */
    @NotNull
    private List<SelectElementNode> getInstancesByClassifier(String projectId, String classifier) {
        try {
            return Optional.ofNullable(simulationService.queryInstancesByClassifier(projectId, classifier))
                    .map(SelectElementNode::getChildren)
                    .filter(CollectionUtils::isNotEmpty)
                    .map(e -> {
                        List<SelectElementNode> instances = new ArrayList<>();
                        getPropertySetInstance(e, instances);
                        return instances;
                    }).orElse(Collections.emptyList());
        } catch (Exception e) {
            log.error("", e);
            return Collections.emptyList();
        }
    }

    /**
     * 根据id获得属性集模型信息
     *
     * @param projectId 项目id
     * @param ids       id集合
     * @return 度量集
     */
    @NotNull
    private List<InstanceVo> getPropertySet(String projectId, List<String> ids) {
        return Optional.ofNullable(ids)
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> internalUmlService.fetchInstanceByIds(e, projectId))
                .filter(CollectionUtils::isNotEmpty)
                .map(instances -> {
                    Map<String, Collection<String>> stereotypeMap = instances.stream()
                            .filter(Objects::nonNull)
                            .collect(Collectors.toMap(
                                            BasicRElement::getId,
                                            MetaClassInstance::getAppliedStereotypes,
                                            (i, j) -> j
                                    )
                            );
                    Map<String, String> nameMap = getName(projectId, instances);

                    List<InstanceVo> propertySet = new ArrayList<>();
                    ids.forEach(e -> {
                        InstanceVo vo = new InstanceVo();
                        Optional.ofNullable(stereotypeMap.get(e))
                                .filter(CollectionUtils::isNotEmpty)
                                .filter(i -> i.stream().anyMatch(k -> Objects.equals(k, UMLDefinitionConstants.UAF_MeasurementSet)))
                                .ifPresent(i -> {
                                    vo.setId(e);
                                    propertySet.add(vo);
                                });
                        Optional.ofNullable(nameMap.get(e))
                                .filter(StringUtils::isNotBlank)
                                .ifPresent(vo::setName);
                    });
                    return propertySet;
                }).orElse(Collections.emptyList());
    }

    /**
     * 获得实际度量列表
     *
     * @param projectId   项目id
     * @param propertySet 属性集
     * @return 实际度量
     */
    @NotNull
    private List<InstanceVo> getActualMeasurements(String projectId, MetaClassInstance propertySet) {
        if (ClassTypeEnum.dataType(Objects.requireNonNull(propertySet.getMetaClass()).getId())) {
            List<SelectElementNode> instances = getInstancesByClassifier(projectId, propertySet.getId());
            return Optional.of(instances.stream().map(SelectElementNode::getInstanceId).collect(Collectors.toList()))
                    .filter(CollectionUtils::isNotEmpty)
                    .map(e -> internalUmlService.fetchInstanceByIds(e, projectId))
                    .filter(CollectionUtils::isNotEmpty)
                    .map(instanceList -> {
                        List<InstanceVo> actualMeasurements = new ArrayList<>();
                        Map<String, String> map = instances.stream()
                                .filter(e -> StringUtils.isNotBlank(e.getInstanceId()))
                                .collect(Collectors.toMap(
                                        SelectElementNode::getInstanceId,
                                        SelectElementNode::getName,
                                        (i, j) -> j));

                        instanceList.forEach(k ->
                                Optional.of(k)
                                        .map(e -> internalUmlService.queryListInstanceProperty(
                                                projectId, e, UMLDefinitionConstants.InstanceSpecification_slot))
                                        .filter(CollectionUtils::isNotEmpty)
                                        .map(e -> getSlots(projectId, e, map.get(k.getId())))
                                        .filter(CollectionUtils::isNotEmpty)
                                        .ifPresent(actualMeasurements::addAll)
                        );
                        return actualMeasurements;
                    }).orElse(Collections.emptyList());
        } else {
            return getActualMeasurementsOfClass(projectId, propertySet);
        }
    }

    /**
     * 根据实例和前缀信息，获得插槽列表信息
     *
     * @param projectId 项目id
     * @param instances 实例
     * @param prefix    前缀
     * @return 插槽
     */
    @NotNull
    private List<InstanceVo> getSlots(String projectId, List<MetaClassInstance> instances, String prefix) {
        return Optional.ofNullable(instances)
                .filter(CollectionUtils::isNotEmpty)
                .map(slotList -> Optional.of(modelPropertyInfoService.createModelPropertyInfoList(projectId,
                                slotList, Collections.singletonList(UMLDefinitionConstants.Slot_definingFeature)))
                        .filter(CollectionUtils::isNotEmpty)
                        .map(slots -> {
                            List<MetaClassInstance> instanceList = new ArrayList<>();
                            Map<String, MetaClassInstance> typeMap = new HashMap<>();

                            slots.forEach(slot -> {
                                Optional.ofNullable(slot.queryInstanceValue(UMLDefinitionConstants.Slot_definingFeature))
                                        .ifPresent(e -> typeMap.put(slot.getInstanceId(), e));
                                instanceList.add(slot.getInstance());
                            });

                            Map<String, String> slotType = getNames(projectId, typeMap);
                            Map<String, List<MetaClassInstance>> slotValue = getSlotValue(projectId, instanceList);
                            List<InstanceVo> list = new ArrayList<>();

                            slots.forEach(slot -> {
                                InstanceVo vo = new InstanceVo();
                                list.add(vo);
                                vo.setId(slot.getInstanceId());

                                MetaClassInstance instance = slot.getInstance();
                                Optional.ofNullable(instance.getAppliedStereotypes())
                                        .filter(CollectionUtils::isNotEmpty)
                                        .ifPresent(e -> vo.setAppliedStereotypes(new ArrayList<>(e)));
                                Optional.ofNullable(instance.getMetaClass())
                                        .ifPresent(e -> vo.setMetaClass(e.getName()));
                                vo.setOwnerId(instance.getOwnerId());

                                String propName = Optional.ofNullable(typeMap.get(instance.getId()))
                                        .filter(e -> StringUtils.isNotBlank(e.getId()))
                                        .map(BasicRElement::getId)
                                        .map(slotType::get)
                                        .orElse(null);

                                SlotAttr attr = new SlotAttr();
                                ShowAttribute<SlotAttr> showAttribute = new ShowAttribute<>();
                                showAttribute.setExtraAttribute(attr);
                                vo.setShowAttribute(showAttribute);

                                Optional.ofNullable(propName)
                                        .filter(StringUtils::isNotBlank)
                                        .ifPresent(e -> {
                                            attr.setSlotPropertyName(e);
                                            attr.setSlotLabel(prefix + ":" + e);
                                            attr.setSlotValues(Collections.emptyList());
                                        });

                                Optional.of(slotValue.get(instance.getId()))
                                        .filter(CollectionUtils::isNotEmpty)
                                        .filter(s -> StringUtils.isNotBlank(propName))
                                        .flatMap(k -> Optional.of(k.stream()
                                                        .map(v -> internalSpecificationService.queryValueFromValueSpecification(projectId, v))
                                                        .collect(Collectors.toList()))
                                                .filter(CollectionUtils::isNotEmpty))
                                        .ifPresent(v -> {
                                            ValueSpecificationInfo value = v.get(0);
                                            attr.setSlotValues(v.stream()
                                                    .map(ValueSpecificationInfo::getName)
                                                    .filter(StringUtils::isNotBlank)
                                                    .collect(Collectors.toList()));

                                            attr.setSlotValueType(value.getMetaclass());
                                            attr.setSlotLabel(prefix + ":" + propName + "=" +
                                                    String.join(",", attr.getSlotValues()));
                                        });
                            });
                            return list;
                        }).orElse(Collections.emptyList())).orElse(Collections.emptyList());
    }

    /**
     * 根据实例获得插槽值map
     *
     * @param projectId 项目id
     * @param instances 实例
     * @return 插槽值
     */
    @NotNull
    private Map<String, List<MetaClassInstance>> getSlotValue(String projectId, List<MetaClassInstance> instances) {
        return Optional.ofNullable(instances)
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> getSlotValues(projectId, e))
                .filter(CollectionUtil::isNotEmpty)
                .orElse(Collections.emptyMap());
    }

    /**
     * 根据插槽值map，获得插槽名称map
     *
     * @param projectId   项目id
     * @param instanceMap 实例
     * @return 名称
     */
    @NotNull
    private Map<String, String> getNames(String projectId, Map<String, MetaClassInstance> instanceMap) {
        return Optional.ofNullable(instanceMap)
                .filter(CollectionUtil::isNotEmpty)
                .map(Map::values)
                .filter(CollectionUtil::isNotEmpty)
                .map(HashSet::new)
                .map(ArrayList::new)
                .map(e -> getName(projectId, e))
                .filter(CollectionUtil::isNotEmpty)
                .orElse(Collections.emptyMap());
    }

    /**
     * 获得指定属性集的度量模型列表
     *
     * @param projectId   项目id
     * @param propertySet 属性集
     * @return 度量
     */
    @NotNull
    private List<MetaClassInstance> getMeasurements(String projectId, MetaClassInstance propertySet) {
        return internalUmlService.queryListInstanceProperty(projectId, propertySet, UMLDefinitionConstants.Namespace_member)
                .stream()
                .filter(e -> CollectionUtils.isNotEmpty(e.getAppliedStereotypes()))
                .filter(e -> e.getAppliedStereotypes().contains(UMLDefinitionConstants.UAF_Measurement))
                .collect(Collectors.toList());
    }

    /**
     * 获得类的实际度量集列表
     *
     * @param projectId   项目id
     * @param propertySet 属性集
     * @return 实际度量
     */
    @NotNull
    private List<InstanceVo> getActualMeasurementsOfClass(String projectId, MetaClassInstance propertySet) {
        return Optional.of(getMeasurements(projectId, propertySet))
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> e.stream().map(BasicRElement::getId).collect(Collectors.toList()))
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> getType(projectId, internalUmlService.fetchInstanceByIds(e, projectId)))
                .filter(CollectionUtil::isNotEmpty)
                .map(Map::values)
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> new ArrayList<>(new HashSet<>(e)))
                .map(e -> internalUmlService.fetchInstanceByIds(e, projectId))
                .filter(CollectionUtils::isNotEmpty)
                .map(e -> {
                    List<InstanceVo> actualState = new ArrayList<>();
                    e.forEach(v -> actualState.addAll(getActualMeasurements(projectId, v)));
                    return actualState;
                }).orElse(Collections.emptyList());
    }

    /**
     * 根据选择节点，获得度量集实例
     *
     * @param nodes     可选择节点
     * @param instances 结果集
     */
    private void getPropertySetInstance(List<SelectElementNode> nodes, List<SelectElementNode> instances) {
        if (CollectionUtils.isNotEmpty(nodes)) {
            nodes.forEach(e -> {
                if (StringUtils.isNotBlank(e.getName())) {
                    instances.add(e);
                }
                getPropertySetInstance(e.getChildren(), instances);
            });
        }
    }
}